import {
  Action,
  AuthService,
  fromJwt,
  fromParam,
  fromResponseSingle,
  JwtPayload,
  JwtPayloadDto,
  PermissionsTo,
  Token,
} from '@boticord/auth'
import { Body, Controller, Get, Param, Patch, Post } from '@nestjs/common'
import { AuthorizeDto, UpdatePermissionsDto } from '@boticord/users-client'
import { UsersService } from '../services/users.service'
import { AnalyseRequest, EventTypes } from '@boticord/analytics'

@Controller('auth')
export class AuthController {
  constructor(private readonly auth: AuthService, private readonly users: UsersService) {}

  /** get authorization token for a user */
  @Post('authorize')
  @AnalyseRequest(EventTypes.Login, { user: fromResponseSingle('id') })
  async authorize(@Body() authorize: AuthorizeDto) {
    const { token, userData } = await this.auth.authorizeWithData(authorize.code, authorize.redirect)

    // === ONLY IN BETA ===
    // const member = await this.users.bot.getMember('722424773233213460', userData.id)
    // const hasBeta = member?.roles.includes('944919099870429214')
    // console.log('DEBUG', userData, member, member?.roles, hasBeta)
    //
    // if (!hasBeta) {
    //   throw new ForbiddenException({ code: ErrorCodes.BetaOnly })
    // }

    await this.users.populateCacheUsingDiscord(userData.id)
    return { token, id: userData.id }
  }

  /** refresh authorization token for a user */
  @Post('refresh')
  // set action to BearerToken to check if user has a valid token, but don't require any permissions
  @PermissionsTo(Action.BearerToken, Token)
  @AnalyseRequest(EventTypes.Login, { user: fromJwt('id') })
  async refresh(@JwtPayload() payload: JwtPayloadDto) {
    return { token: await this.auth.newUserToken(payload.id, payload.redirect) }
  }

  /** edit user permissions */
  @Patch('permissions/:id')
  @PermissionsTo(Action.Modify, Token)
  async updatePermissions(@Param('id') id: string, @Body() body: UpdatePermissionsDto) {
    await this.auth.setUserPermissions(id, body.permissions)
    return { userID: id, permissions: body.permissions }
  }

  /** get user permissions */
  @Get('permissions/:id')
  @PermissionsTo(Action.Read, Token, { fetch: { id: fromParam('id') } })
  async getPermissions(@Param('id') id: string) {
    // if permitted, can read other users permissions too
    return { userID: id, permissions: await this.auth.getPermissions(id) }
  }
}
